﻿namespace Refract.MVVM
{
    using System.ComponentModel;
    using System.Threading;
    using System.Windows;
    using System.Windows.Browser;
    using System.Windows.Controls;

    /// <summary>
    /// Base class for views
    /// </summary>
    /// <remarks>Views implement front-end functionality</remarks>
    public class View : UserControl, INotifyPropertyChanged, IView
    {
        #region Events

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion Events

        #region Properties

        public new object DataContext
        {
            get { return base.DataContext as IViewModel; }
            set
            {
                var viewModel = base.DataContext as IViewModel;
                if (viewModel != null)
                    viewModel.ViewClosed -= ViewModel_ViewClosed;

                base.DataContext = value;
                viewModel = base.DataContext as IViewModel;
                if (viewModel != null)
                    viewModel.ViewClosed += ViewModel_ViewClosed;

                RaisePropertyChanged(new { DataContext });
            }
        }

        /// <summary>
        /// Gets a value indicating whether the app is running in design mode.
        /// </summary>
        /// <value>
        /// 	<c>true</c> if this app is in design mode; otherwise, <c>false</c>.
        /// </value>
        protected static bool IsDesignMode
        {
            get
            {
                return HtmlPage.IsEnabled == false;
            }
        }

        #endregion Properties

        #region Methods

        public virtual void Close()
        {
            if (Parent == null) return;
            DataContext = null;

            Panel parentPanel = Parent as Panel;
            if(parentPanel != null)
            {
                parentPanel.Children.Remove(this);
            }

            Border parentBorder = Parent as Border;
            if (parentBorder != null)
                parentBorder.Child = null;
        }

        public TViewModel GetViewModel<TViewModel>()
            where TViewModel : class
        {
            return DataContext as TViewModel;
        }

        public virtual void Show(UIElement parent)
        {
            Panel parentPanel = parent as Panel;
            if (parentPanel != null)
            {
                parentPanel.Children.Add(this);
                return;
            }

            Border parentBorder = parent as Border;

            if (parentBorder != null)
            {
                View previousView = parentBorder.Child as View;
                if (previousView != null) previousView.Close();
                parentBorder.Child = this;
            }
        }

        /// <summary>
        /// Raises the property changed event.
        /// </summary>
        /// <param name="propertyName">Name of the property that changed.</param>
        protected void RaisePropertyChanged(string propertyName)
        {
            if (PropertyChanged == null) return;

            if (Dispatcher != null && !Dispatcher.CheckAccess())
            {
                Dispatcher.BeginInvoke
                    (
                        (ThreadStart)(() => PropertyChanged(this, new PropertyChangedEventArgs(propertyName)))
                    );
            }
            else
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        protected void RaisePropertyChanged<T>(T propertyContainer)
            where T : class
        {
            RaisePropertyChanged(Component.GetVariableName(propertyContainer));
        }

        void ViewModel_ViewClosed(object sender, System.EventArgs e)
        {
            Close();
        }

        #endregion Methods
    }
}